﻿#include "ModulesManager.h"

#include "../../Utils/Logger.h"

std::map<std::u8string, IModule*> ModuleManager::NameTable{};
std::shared_mutex ModuleManager::moduleListMutex{};

void ModuleManager::initModules() {
	Logger::LogC(LogGrade::info, u8"Modules Init!");
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		moduleList[i]->_init();
	}
}

void ModuleManager::disable() {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		if (auto mod = moduleList[i]; mod->isEnabled()) {
			mod->last_enbale = true;
			mod->setEnabled(false);
		}
	}
}

void ModuleManager::onLoadConfig(nlohmann::json& conf) {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		moduleList[i]->onLoadConfig(conf);
	}
}

void ModuleManager::onSaveConfig(nlohmann::json& conf) {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		moduleList[i]->onSaveConfig(conf);
	}
}

void ModuleManager::onTick(C_GameMode* gameMode) {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		if (auto mod = moduleList[i]; mod->isEnabled()) 
			mod->_onTick(gameMode);
	}
}

void ModuleManager::onAttack(C_Entity* attackedEnt) {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		if (auto mod = moduleList[i]; mod->isEnabled())
			mod->_onAttack(attackedEnt);
	}
}

void ModuleManager::onWorldTick(C_GameMode* gameMode) {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		if (auto mod = moduleList[i]; mod->isEnabled()) 
			mod->_onWorldTick(gameMode);
	}
}

void ModuleManager::onKeyUpdate(uint8_t key, bool isDown) {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		moduleList[i]->_onKeyUpdate(key, isDown);
	}
}

void ModuleManager::onPreRender(C_MinecraftUIRenderContext* renderCtx) {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		if (auto mod = moduleList[i]; mod->isEnabled())
			mod->_onPreRender(renderCtx);
	}
}

void ModuleManager::onPostRender(C_MinecraftUIRenderContext* renderCtx) {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		if (auto mod = moduleList[i]; mod->isEnabled())
			mod->_onPostRender(renderCtx);
	}
}

void ModuleManager::onLevelRender() {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		if (auto mod = moduleList[i]; mod->isEnabled())
			mod->_onLevelRender();
	}
}

void ModuleManager::onMove(C_MoveInputHandler* handler) {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		if (auto mod = moduleList[i]; mod->isEnabled()) 
			mod->_onMove(handler);
	}
}

void ModuleManager::onSendPacket(C_Packet* packet, bool& cancelSend) {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		if (auto mod = moduleList[i]; mod->isEnabled()) 
			mod->_onSendPacket(packet, cancelSend);
	}
}

void ModuleManager::onPlayerTick(C_Player* player) {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		if (auto mod = moduleList[i]; mod->isEnabled()) 
			mod->_onPlayerTick(player);
	}
}

void ModuleManager::onGetPickRange() {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		if (auto mod = moduleList[i]; mod->isEnabled())
			mod->_onGetPickRange();
	}
}

void ModuleManager::onUpdate() {
	[[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++) {
		if (auto mod = moduleList[i]; mod->isEnabled())
			mod->_onUpdate();
	}
}

size_t ModuleManager::getEnabledModuleCount() {
	// [[maybe_unused]] auto lock = std::shared_lock(moduleListMutex);
	size_t num = 0;
	constexpr size_t modulecount = getModuleCount();
	for (size_t i = 0; i < modulecount; i++)
		if (moduleList[i]->isEnabled())
			++num;
	return num;
}

IModule* ModuleManager::getModuleByName(const std::u8string_view name) {
	std::u8string n(name);
	std::ranges::for_each(n, [](char8_t& str) { str = fast_io::char_category::to_c_lower(str); });
	if (auto f = NameTable.find(n); f != NameTable.end())
		return f->second;
	else
		return nullptr;
}
